from __future__ import with_statement
import threading
import random
import logging
import pprint
import Hex as HexMod
import Vertex
import Edge
import Road
import jsonpickle
  
class GameContext:
  next_id = 0
  lock = threading.Lock()
  
  def __init__(self, host, hexes, edges, vertices, players):
    self.host = host
    with self.__class__.lock:
      self.id = self.__class__.next_id
      self.__class__.next_id += 1
    self.hexes = hexes
    self.edges = edges
    self.thief_hex_id = self.get_chosen_hexes(7)[0].id
    self.vertices = vertices
    self.players = players
    self.dice = [Die(), Die()]
    self.cur_player = 0
    self.winner_player = -1
    self.game_state = GameState.WAITING_FOR_START
    
  def summary(self):
    return "cp %d, wp %d, dice %s, gs %s, nedges %d, nver %d, nplayers %d, {%s}"\
      %(self.cur_player, self.winner_player, self.dice, 
        self.game_state, 
        len([edge for edge in self.edges if edge.road]), 
        len([vertex for vertex in self.vertices if vertex.building]), 
        len(self.players), 
        [player.summary() for player in self.players])
  
  def roll_dice(self):
    for die in self.dice:
      die.shuffle()
  
  def set_thief_hex_id(self, hex_id):
    self.thief_hex_id = hex_id

  def set_dice(self, vals):
    for i,val in enumerate(vals):
      self.dice[i].val = val
  
  # returns true if the game is over
  def update_points(self):
    longest_paths = [Road.get_longest_path(player.roads) for player in self.players]
    longest_path = max(longest_paths)
    longest_path_idx = -1
    if longest_path:
      longest_path_idx = longest_paths.index(longest_path)
    for idx, player in enumerate(self.players):
      player.update_points(longest_path_idx == idx)

    player_points = [player.get_points() for player in self.players]
    max_points = max(player_points)
    if max_points > 13:
      self.winner_player = player_points.index(max_points)
      self.game_state = GameState.GAME_ENDED
      return True
    else:
      return False
  
  def get_chosen_hexes(self, total = None):
    if not total:
      total = sum([die.val for die in self.dice])
    chosen_hexes = [hex for hex in self.hexes if hex.number == total]
    return chosen_hexes
  
  def distr_resources(self, pay_all = False):
    chosen_hexes = self.get_chosen_hexes() if not pay_all  else self.hexes
    paying_vertices = reduce(lambda x,y: y+x, 
                             [vertices for hex, vertices in HexMod.hex_to_vertex_map.items() if hex in 
                             map(lambda x: x.id, chosen_hexes)], [])
    for player in self.players:
      building_vertices = map(lambda b: b.vertex, player.buildings)
      for building_vertex in building_vertices:
        if building_vertex in paying_vertices: 
          hexes = HexMod.vertex_to_hex_map[building_vertex]
          for hex in hexes:
            if self.hexes[hex] in chosen_hexes and not hex == self.thief_hex_id:
#              logging.error("chosen_hexes %s, paying vertices %s building_vertices %s cur_hex %s" % (chosen_hexes, paying_vertices, building_vertices, self.hexes[hex]))
              player.update_resources({self.hexes[hex].type:1})
    for player in self.players:
      logging.debug(player)
      
  def __repr__(self):
#    string = "host=[" + str(self.host) + "]\n"
#    string += "hexes=[" + str(self.hexes) + "]\n"
#    non_empty_edges = [edge for edge in self.edges if edge.road != None]
#    string += "non_empty_edges=[" + str(non_empty_edges) + "]\n"
#    non_empty_vertices = [vertex for vertex in self.vertices if vertex.building != None]
#    string += "non_empty_vertices=[" + str(non_empty_vertices) + "]\n"
#    string += "players=[" + str([player for player in self.players]) + "]\n"
#    string += "cur_player=[" + str(self.cur_player) + "]\n"
#    string += "winning_player=[" + str(self.winner_player) + "]\n"
#    string += "game_state=[" + str(self.game_state) + "]\n"
#    string += "dice=[" + str(self.dice) + "]\n"
    string = ""
    return string
  
#    total = sum(filter(lambda die: die.type == Die.DieType.Num, self.dice))
#    print total
#    for hex in hexes: 
  
  def next_player(self):
    if (self.game_state == GameState.INIT1):
      if (self.cur_player != len(self.players) - 1):
        self.cur_player += 1
        self.cur_player %= len(self.players)
      else:
        self.game_state = GameState.INIT2
      logging.debug("cur player %s", self.players[self.cur_player])  
      logging.debug("game state is %s", self.game_state)  
    elif (self.game_state == GameState.INIT2):
      if (self.cur_player != 0):
        self.cur_player -= 1
        self.cur_player %= len(self.players)
      else:
        self.game_state = GameState.PLAYING_GAME
      logging.debug("cur player %s", self.players[self.cur_player])  
      logging.debug("game state is %s", self.game_state)  
    elif (self.game_state == GameState.PLAYING_GAME):
      self.cur_player += 1
      self.cur_player %= len(self.players)
      logging.debug("cur player %s", self.players[self.cur_player])  
      logging.debug("game state is %s", self.game_state)  

class GameState:
  WAITING_FOR_START = 0
  INIT1 = 1
  INIT2 = 2
  PLAYING_GAME = 3
  GAME_ENDED = 4

class Die:
  
  def __init__(self, val = 1):
    self.val = val
    
  def shuffle(self):
    self.val = random.randint(1,6)
    
  def __repr__(self):
    return "%d" % (self.val)
    
from Player import Player
from ResourceType import ResourceType
from Hex import Hex

def init_game_context(token):
  # create default GameContext
  player = Player(token)
  index = 0
  init_hexes = []
  init_hexes.append(Hex(11, ResourceType.Forest,id=0))
  init_hexes.append(Hex(12, ResourceType.Sheep,id=1))
  init_hexes.append(Hex(9, ResourceType.Grain,id=2))
  init_hexes.append(Hex(4, ResourceType.Brick,id=3))
  init_hexes.append(Hex(6, ResourceType.Ore,id=4))
  init_hexes.append(Hex(5, ResourceType.Brick,id=5))
  init_hexes.append(Hex(10, ResourceType.Sheep,id=6))
  init_hexes.append(Hex(7, ResourceType.Desert,id=7))
  init_hexes.append(Hex(3, ResourceType.Forest,id=8))
  init_hexes.append(Hex(11, ResourceType.Grain,id=9))
  init_hexes.append(Hex(4, ResourceType.Forest,id=10))
  init_hexes.append(Hex(8, ResourceType.Grain,id=11))
  init_hexes.append(Hex(8, ResourceType.Brick,id=12))
  init_hexes.append(Hex(10, ResourceType.Sheep,id=13))
  init_hexes.append(Hex(9, ResourceType.Sheep,id=14))
  init_hexes.append(Hex(3, ResourceType.Ore,id=15))
  init_hexes.append(Hex(5, ResourceType.Ore,id=16))
  init_hexes.append(Hex(2, ResourceType.Grain,id=17))
  init_hexes.append(Hex(6, ResourceType.Forest,id=18))
  init_vertices = []
  for vertex_id in range(54):
    init_vertices.append(Vertex.Vertex(vertex_id))
  init_edges = []
  for edge_id in range(72):
    init_edges.append(Edge.Edge(edge_id))

  game_context = GameContext(host = index, hexes = init_hexes, edges = init_edges, vertices = init_vertices, players = [player])
  return game_context


#context = init_game_context("bla")
#context.roll_dice()
#context.compute_payout()

